from django.conf import settings
import requests
import logging
from typing import Dict, List, Optional, Union
import os

logger = logging.getLogger('apps')

class OCRServiceError(Exception):
    """OCR服务异常"""
    def __init__(self, message, code=None, http_status=500):
        self.message = message
        self.code = code
        self.http_status = http_status
        super().__init__(message)

class OCRService:
    """OCR服务类 使用 Textin API"""
    def __init__(self):
        self.config = settings.AI_CONFIG.get('ocr_service', {})
        self.app_id = self.config.get('app_id', '1a4137efec74924d48c7f79d130340f9')
        self.secret_code = self.config.get('secret_code', 'a1b14d43c208cba6f18f856784f7ed71')
        self.api_url = 'https://api.textin.com/ai/service/v2/recognize/multipage'
        self.max_retries = self.config.get('max_retries', 3)
        self.timeout = self.config.get('timeout', 30)

    def recognize_text(self, image_file, options: Dict = None) -> str:
        """识别图片中的文字
        
        Args:
            image_file: 图片文件对象
            options: 识别选项，可包含以下参数：
                - character: 是否返回完整字符信息 (0或1)
                - straighten: 坐标系选项 (0或1)
                - language: 语言，默认自动检测
            
        Returns:
            str: 识别出的文本
        """
        try:
            # 验证图片
            if not self.validate_image(image_file):
                raise OCRServiceError("图片验证失败，请检查图片格式和大小", code="INVALID_IMAGE")
            
            # 准备请求头
            headers = {
                'x-ti-app-id': self.app_id,
                'x-ti-secret-code': self.secret_code,
                'Content-Type': 'application/octet-stream'
            }
            
            # 准备URL参数
            params = {}
            if options:
                if 'character' in options:
                    params['character'] = options.get('character', 0)
                if 'straighten' in options:
                    params['straighten'] = options.get('straighten', 0)
            
            # 读取图片内容
            image_content = image_file.read()
            
            # 发送请求，带重试机制
            response = None
            for retry in range(self.max_retries):
                try:
                    response = requests.post(
                        self.api_url,
                        headers=headers,
                        params=params,
                        data=image_content,
                        timeout=self.timeout
                    )
                    
                    # 检查响应状态
                    if response.status_code == 200:
                        break
                    
                    # 如果是服务器错误，重试
                    if response.status_code >= 500:
                        logger.warning(f"OCR API服务器错误，重试 {retry+1}/{self.max_retries}: {response.status_code}")
                        continue
                        
                    # 其他错误，直接抛出
                    logger.error(f"OCR API请求失败: {response.status_code}, {response.text}")
                    raise OCRServiceError(f"OCR API请求失败: {response.status_code}", 
                                         code=f"HTTP_{response.status_code}")
                        
                except requests.RequestException as e:
                    logger.warning(f"OCR API请求异常，重试 {retry+1}/{self.max_retries}: {str(e)}")
                    if retry == self.max_retries - 1:
                        raise OCRServiceError(f"OCR API请求异常: {str(e)}", code="REQUEST_ERROR")
            
            if not response:
                raise OCRServiceError("OCR API请求失败，无响应", code="NO_RESPONSE")
                
            # 解析响应
            result = response.json()
            
            # 检查响应码
            if result.get('code') != 200:
                logger.error(f"OCR识别失败: {result.get('message')}")
                raise OCRServiceError(f"OCR识别失败: {result.get('message')}", 
                                     code=f"API_{result.get('code')}")
            
            # 提取文本
            text = self._process_textin_result(result)
            
            # 记录识别结果
            logger.info(f"OCR识别成功，文本长度: {len(text)}")
            
            return text
            
        except OCRServiceError:
            # 直接抛出已经格式化的错误
            raise
        except Exception as e:
            logger.error(f"OCR识别失败: {str(e)}", exc_info=True)
            raise OCRServiceError(f"OCR识别失败: {str(e)}", code="UNKNOWN_ERROR")

    def recognize_text_from_url(self, image_url: str, options: Dict = None) -> str:
        """从URL识别图片中的文字
        
        Args:
            image_url: 图片URL
            options: 识别选项，同recognize_text
            
        Returns:
            str: 识别出的文本
        """
        try:
            # 验证URL
            if not image_url or not (image_url.startswith('http://') or image_url.startswith('https://')):
                raise OCRServiceError("无效的图片URL", code="INVALID_URL")
            
            # 准备请求头
            headers = {
                'x-ti-app-id': self.app_id,
                'x-ti-secret-code': self.secret_code,
                'Content-Type': 'text/plain'
            }
            
            # 准备URL参数
            params = {}
            if options:
                if 'character' in options:
                    params['character'] = options.get('character', 0)
                if 'straighten' in options:
                    params['straighten'] = options.get('straighten', 0)
            
            # 发送请求，带重试机制
            response = None
            for retry in range(self.max_retries):
                try:
                    response = requests.post(
                        self.api_url,
                        headers=headers,
                        params=params,
                        data=image_url,
                        timeout=self.timeout
                    )
                    
                    # 检查响应状态
                    if response.status_code == 200:
                        break
                    
                    # 如果是服务器错误，重试
                    if response.status_code >= 500:
                        logger.warning(f"OCR API服务器错误，重试 {retry+1}/{self.max_retries}: {response.status_code}")
                        continue
                        
                    # 其他错误，直接抛出
                    logger.error(f"OCR API请求失败: {response.status_code}, {response.text}")
                    raise OCRServiceError(f"OCR API请求失败: {response.status_code}", 
                                         code=f"HTTP_{response.status_code}")
                        
                except requests.RequestException as e:
                    logger.warning(f"OCR API请求异常，重试 {retry+1}/{self.max_retries}: {str(e)}")
                    if retry == self.max_retries - 1:
                        raise OCRServiceError(f"OCR API请求异常: {str(e)}", code="REQUEST_ERROR")
            
            if not response:
                raise OCRServiceError("OCR API请求失败，无响应", code="NO_RESPONSE")
                
            # 解析响应
            result = response.json()
            
            # 检查响应码
            if result.get('code') != 200:
                logger.error(f"OCR识别失败: {result.get('message')}")
                raise OCRServiceError(f"OCR识别失败: {result.get('message')}", 
                                     code=f"API_{result.get('code')}")
            
            # 提取文本
            text = self._process_textin_result(result)
            
            # 记录识别结果
            logger.info(f"OCR URL识别成功，文本长度: {len(text)}")
            
            return text
            
        except OCRServiceError:
            # 直接抛出已经格式化的错误
            raise
        except Exception as e:
            logger.error(f"OCR URL识别失败: {str(e)}", exc_info=True)
            raise OCRServiceError(f"OCR URL识别失败: {str(e)}", code="UNKNOWN_ERROR")

    def validate_image(self, image_file) -> bool:
        """验证图片
        
        Args:
            image_file: 图片文件对象
            
        Returns:
            bool: 是否验证通过
        """
        try:
            # 检查文件大小
            max_size = self.config.get('max_file_size', 500 * 1024 * 1024)  # 默认500MB
            if image_file.size > max_size:
                logger.warning(f"图片大小超过限制: {image_file.size} > {max_size}")
                return False
            
            # 检查文件格式
            allowed_formats = self.config.get('allowed_formats', ['jpg', 'jpeg', 'png', 'bmp', 'pdf', 'tiff', 'gif'])
            file_ext = image_file.name.split('.')[-1].lower()
            if file_ext not in allowed_formats:
                logger.warning(f"图片格式不支持: {file_ext}, 支持的格式: {allowed_formats}")
                return False
                
            return True
            
        except Exception as e:
            logger.error(f"图片验证失败: {str(e)}")
            return False

    def _process_textin_result(self, result: Dict) -> str:
        """处理Textin OCR结果
        
        Args:
            result: Textin API返回的结果
            
        Returns:
            str: 提取的文本
        """
        try:
            all_text = []
            
            # 遍历所有页面
            for page in result.get('result', {}).get('pages', []):
                page_lines = []
                
                # 遍历页面中的所有文本行
                for line in page.get('lines', []):
                    text = line.get('text', '').strip()
                    if text:
                        # 根据文本类型添加不同的处理
                        text_type = line.get('type', 'text')
                        if text_type == 'formula':
                            # 对公式类型特殊处理
                            page_lines.append(f"[公式] {text}")
                        elif text_type == 'stamp':
                            # 对印章类型特殊处理
                            page_lines.append(f"[印章] {text}")
                        else:
                            page_lines.append(text)
                
                # 将页面文本合并，每行一个换行符
                if page_lines:
                    all_text.append('\n'.join(page_lines))
            
            # 将所有页面文本合并，每页之间用两个换行符分隔
            return '\n\n'.join(all_text)
            
        except Exception as e:
            logger.error(f"处理OCR结果失败: {str(e)}")
            return ""

    def get_text_structure(self, ocr_result: Dict) -> Dict:
        """获取文本结构化信息
        
        Args:
            ocr_result: OCR识别结果
            
        Returns:
            Dict: 结构化信息
        """
        try:
            # 提取标题
            title = self._extract_title(ocr_result)
            
            # 提取段落
            paragraphs = self._extract_paragraphs(ocr_result)
            
            # 提取表格
            tables = self._extract_tables(ocr_result)
            
            # 提取关键信息
            key_info = self._extract_key_info(ocr_result)
            
            return {
                'title': title,
                'paragraphs': paragraphs,
                'tables': tables,
                'key_info': key_info
            }
            
        except Exception as e:
            logger.error(f"获取文本结构失败: {str(e)}")
            return {
                'title': '',
                'paragraphs': [],
                'tables': [],
                'key_info': {}
            }

    def _extract_title(self, ocr_result: Dict) -> str:
        """提取标题
        
        Args:
            ocr_result: OCR识别结果
            
        Returns:
            str: 标题
        """
        # 实现标题提取逻辑
        # 通常第一页的第一行文本，且字体较大
        try:
            if 'result' in ocr_result and 'pages' in ocr_result['result'] and ocr_result['result']['pages']:
                first_page = ocr_result['result']['pages'][0]
                if 'lines' in first_page and first_page['lines']:
                    # 取第一行作为标题
                    return first_page['lines'][0].get('text', '')
            return ''
        except Exception:
            return ''

    def _extract_paragraphs(self, ocr_result: Dict) -> List[str]:
        """提取段落
        
        Args:
            ocr_result: OCR识别结果
            
        Returns:
            List[str]: 段落列表
        """
        # 实现段落提取逻辑
        paragraphs = []
        try:
            if 'result' in ocr_result and 'pages' in ocr_result['result']:
                for page in ocr_result['result']['pages']:
                    if 'lines' in page:
                        current_paragraph = []
                        for line in page['lines']:
                            text = line.get('text', '').strip()
                            if text:
                                current_paragraph.append(text)
                            elif current_paragraph:
                                # 空行表示段落结束
                                paragraphs.append(' '.join(current_paragraph))
                                current_paragraph = []
                        
                        # 处理最后一个段落
                        if current_paragraph:
                            paragraphs.append(' '.join(current_paragraph))
            return paragraphs
        except Exception:
            return []

    def _extract_tables(self, ocr_result: Dict) -> List[Dict]:
        """提取表格
        
        Args:
            ocr_result: OCR识别结果
            
        Returns:
            List[Dict]: 表格列表
        """
        # 实现表格提取逻辑
        # 这需要更复杂的算法，可能需要分析文本的位置信息
        return []

    def _extract_key_info(self, ocr_result: Dict) -> Dict:
        """提取关键信息
        
        Args:
            ocr_result: OCR识别结果
            
        Returns:
            Dict: 关键信息
        """
        # 实现关键信息提取逻辑
        # 例如日期、金额、姓名等
        return {}